/*
 * Created on Feb 20, 2005
 * Created by dfhuynh
 */
package edu.mit.simile.longwell.query.project;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;

import edu.mit.simile.longwell.Profile;
import edu.mit.simile.longwell.query.project.ProjectorUtilities.Pair;

/**
 * @author dfhuynh
 */
abstract public class LongValueProjection extends PropertyProjection {
	protected Pair[] m_pairs;
	

	/**
	 * @param profile
	 * @param property
	 * @param forward
	 * @param locale
	 * @param objects
	 */
	public LongValueProjection(
			Profile profile, 
			Property property,
			boolean forward, 
			String locale, 
			Set objects) {
		super(profile, property, forward, locale, objects);
	}

	protected void buildPairs() {
		if (m_pairs != null) {
			return;
		}
		
		Map m = getObjectToValueMap();
		Set objects = getObjects();
		Set keys = m.keySet();
		
		m_pairs = new Pair[keys.size()];
		int index = 0;
		
		Iterator i = keys.iterator();
		while (i.hasNext()) {
			Resource object = (Resource) i.next();
			if (objects.contains(object)) {
				Object	value = m.get(object);
				
				if (value != null) {
					try {
						long l = valueToLong(value);
					
						Pair p = new Pair();
						p.m_object = object;
						p.m_value = l;
						
						m_pairs[index++] = p;
					} catch (Exception e) {
					}
				}
			}
		}
		
		if (index < m_pairs.length) {
			Pair[] pairs = m_pairs;
			m_pairs = new Pair[index];
			
			while (--index >= 0) {
				m_pairs[index] = pairs[index];
			}
		}
		
		m_pairs = ProjectorUtilities.mergeSort(m_pairs, 0, m_pairs.length);
	}
	
	protected long internalGetMin() {
		buildPairs();
		return m_pairs.length > 0 ? 
			(long) m_pairs[0].m_value : Long.MAX_VALUE;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IIntegerProjection#getMax()
	 */
	protected long internalGetMax() {
		buildPairs();
		return m_pairs.length > 0 ? 
			(long) m_pairs[m_pairs.length - 1].m_value : Long.MIN_VALUE;
	}

	
	protected int internalCountObjects(long fromInclusive, long toExclusive) {
		buildPairs();
		if (fromInclusive < toExclusive && m_pairs.length > 0) {
			int startIndex = ProjectorUtilities.lookupIndex(m_pairs, fromInclusive);
			int endIndex = ProjectorUtilities.lookupIndex(m_pairs, toExclusive);
			
			return startIndex < 0 ? 
				(endIndex < 0 ? 0 : endIndex) : 
				((endIndex < 0 ? m_pairs.length : endIndex) - startIndex);
		} else {
			return 0;
		}
	}
	
	protected Set internalGetObjects(long fromInclusive, long toExclusive) {
		buildPairs();
		
		Set objects = new HashSet();
		if (fromInclusive < toExclusive && m_pairs.length > 0) {
			int startIndex = ProjectorUtilities.lookupIndex(m_pairs, fromInclusive);
			int endIndex = ProjectorUtilities.lookupIndex(m_pairs, toExclusive);
			
			if (startIndex >= 0) {
				if (endIndex < 0) {
					endIndex = m_pairs.length;
				}
				
				for (int i = startIndex; i < endIndex; i++) {
					objects.add(m_pairs[i].m_object);
				}
			}
		}
		return objects;
	}
	
	abstract protected long valueToLong(Object v) throws Exception;
}
